package com.taglab.chic.mvc.spring;

import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.mvc.AbstractController;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.util.UrlPathHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Properties;
import java.io.File;

/**
 * Experimental class, needs major work.
 * <p/>
 * XXX add paths to ignore...
 * <p/>
 * XXX allow a controller to be set.
 *
 * @author Markus Kobler
 */
public class PassThroughHandlerMapping extends AbstractHandlerMapping {

  private Logger logger = LoggerFactory.getLogger(PassThroughHandlerMapping.class);

  private String prefix = "";

  private String suffix = ".jsp";

  private String index = "index";

  private boolean lowerCaseUrl = false;

  private Properties viewAttributes;

  private UrlPathHelper urlPathHelper = new UrlPathHelper();

  public void setPrefix(String prefix) {
    this.prefix = prefix;
  }

  public void setSuffix(String suffix) {
    this.suffix = suffix;
  }

  public void setIndex(String index) {
    this.index = index;
  }

  public void setLowerCaseUrls(boolean lowerCaseUrl) {
    this.lowerCaseUrl = lowerCaseUrl;
  }

  public void setViewAttributes(Properties viewAttributes) {
    this.viewAttributes = viewAttributes;
  }

  protected Object getHandlerInternal(HttpServletRequest request) throws Exception {

    String view = lookupView(getResourcePath(request));

    return view != null ? new Controller(view) : null;
  }


  protected String lookupView(String requestURI) throws Exception {

    logger.debug("trying to find '{}'", requestURI);

    if (lowerCaseUrl) {
      requestURI = requestURI.toLowerCase();
    }

    // encode all white space with +
    requestURI = requestURI.replace(' ', '+');

    String path = prefix + requestURI + suffix;

    String realPath = getServletContext().getRealPath(path);

    if (realPath == null || !new File(realPath).exists() || getServletContext().getResource(path) == null) {

      // try without suffix: maybe it's a directory
      path = prefix + requestURI;
      realPath = getServletContext().getRealPath(path);

      if (realPath == null || getServletContext().getResource(path) == null) return null;
    }

    File file = new File(realPath);

    if (file.isDirectory()) {
      if (requestURI.endsWith("/")) {
        path = requestURI + index;
        return lookupView(path);
      } else {
        String viewName = lookupView(requestURI + "/" + index);
        if (viewName != null) {
          String redirectViewName = "redirect:" + requestURI + "/";
          logger.debug("returning: {}", redirectViewName);
          return redirectViewName;
        } else {
          return null;
        }
      }
    } else if (file.isFile()) {
      String viewName = path.substring(prefix.length(), path.length() - suffix.length());
      logger.debug("returning: {}", viewName);
      return viewName;
    }

    logger.debug("file not found: {}", file);
    return null;
  }


  private String getResourcePath(HttpServletRequest request) {
    return urlPathHelper.getLookupPathForRequest(request);
  }

  private class Controller extends AbstractController {

    private String view;

    private Controller(String view) {
      this.view = view;
    }

    protected ModelAndView handleRequestInternal(HttpServletRequest request,
                                                 HttpServletResponse response) throws Exception {

      ModelAndView modelAndView = new ModelAndView(view);

      if (viewAttributes != null && !viewAttributes.isEmpty()) {
        modelAndView.addAllObjects(viewAttributes);
      }

      return modelAndView;
    }

  }

}

